package com.tianquan.miracle.proxy;

import com.tianquan.miracle.aop.JoinPintImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @Author: tianquan
 * @date: 2024-10-08  12:12
 * @Description: CGlib方法调用类，实现MethodInterceptor和MethodInvocation接口 用于创建和管理代理对象的方法调用
 */
public class CglibMethodInvocation implements MethodInterceptor, MethodInvocation {

    /**
     * 需要代理的对象
     */
    private final Object object;

    /**
     * 需要代理的所有方法名称列表
     */
    private final List<String> objectMethodName;

    /**
     * 前置增强方法
     */
    private final Method beforeMethod;

    /**
     * 后置增强方法
     */
    private final Method afterMethod;

    /**
     * 用来调用对应方法的类
     */
    private final Object target;

    /**
     * 环绕增强方法
     */
    private final Method aroundMethod;

    /**
     * 构造函数，初始化代理对象、方法列表和增强方法
     *
     * @param object           需要代理的对象
     * @param objectMethodName 需要代理的方法名称列表
     * @param beforeMethod     前置增强方法
     * @param aroundMethod     环绕增强方法
     * @param afterMethod      后置增强方法
     * @param target           调用增强方法的目标对象
     */
    public CglibMethodInvocation(Object object, List<String> objectMethodName, Method beforeMethod,
                                 Method aroundMethod, Method afterMethod, Object target) {
        this.object = object;
        this.objectMethodName = objectMethodName;
        this.beforeMethod = beforeMethod;
        this.aroundMethod = aroundMethod;
        this.afterMethod = afterMethod;
        this.target = target;
    }

    /**
     * 拦截方法调用，根据方法名称和是否存在增强方法来决定执行流程
     *
     * @param o           代理对象
     * @param method      被调用的方法对象
     * @param objects     方法参数
     * @param methodProxy 方法代理对象
     * @return 方法调用的结果
     * @throws Throwable 如果方法调用过程中出现异常
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        // 如果不是需要代理的方法，则直接调用
        if (!objectMethodName.contains(method.getName())) {
            return method.invoke(this.object, objects);
        }
        Object invoke;
        // 调用前置增强方法
        if (beforeMethod != null) {
            invoke = beforeMethod.invoke(target);
        }
        // 是否有环绕通知
        if (aroundMethod != null) {
            invoke = aroundMethod.invoke(target, new JoinPintImpl(this.object, method, objects));
        } else {
            // 通过反射调用代理类的方法
            invoke = method.invoke(this.object, objects);
        }
        // 调用后置增强方法
        if (afterMethod != null) {
            invoke = afterMethod.invoke(target);
        }
        return invoke;
    }

    /**
     * 获取代理对象
     *
     * @return 代理后的对象
     */
    @Override
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }


}

